//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package project_member_api_serv

import (
	"context"
	"time"

	"atomgit.com/openlinksaas/api-server/api_common"
	"atomgit.com/openlinksaas/api-server/dao"
	"atomgit.com/openlinksaas/api-server/dao/project_dao"
	"atomgit.com/openlinksaas/api-server/dao/user_dao"
	"atomgit.com/openlinksaas/api-server/utils"
	"atomgit.com/openlinksaas/proto-gen-go.git/notices/notices_project"
	"atomgit.com/openlinksaas/proto-gen-go.git/project_member_api"
	"github.com/dchest/uniuri"
	"go.mongodb.org/mongo-driver/mongo"
)

type ProjectMemberApiImpl struct {
	project_member_api.UnimplementedProjectMemberApiServer
}

func (apiImpl *ProjectMemberApiImpl) GenInvite(ctx context.Context, req *project_member_api.GenInviteRequest) (*project_member_api.GenInviteResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_member_api.GenInviteResponse{
			Code:   project_member_api.GenInviteResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_member_api.GenInviteResponse{
			Code:   project_member_api.GenInviteResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_member_api.GenInviteResponse{
			Code:   project_member_api.GenInviteResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_member_api.GenInviteResponse{
			Code:   project_member_api.GenInviteResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	if !(roleItem.BasicInfo.Admin || projectItem.OwnerUserId == sessionItem.UserId) {
		return &project_member_api.GenInviteResponse{
			Code:   project_member_api.GenInviteResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	if req.Ttl < 1 {
		req.Ttl = 1
	}
	if req.Ttl > 24*30 {
		req.Ttl = 24 * 30
	}

	inviteCode := "PRJ" + uniuri.NewLen(61)

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = project_dao.ProjectInviteDao.Insert(sessCtx, &project_dao.ProjectInviteDbItem{
			InviteCode:   inviteCode,
			ProjectId:    req.ProjectId,
			CreateUserId: sessionItem.UserId,
			CreateTime:   time.Now().UnixNano() / 1e6,
			ExpireTime:   time.Now().Add(time.Duration(req.Ttl)*time.Hour).UnixNano() / 1e6,
		})
		if err != nil {
			return nil, err
		}

		return &project_member_api.GenInviteResponse{
			Code:       project_member_api.GenInviteResponse_CODE_OK,
			InviteCode: inviteCode,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//add event
	go apiImpl.addGenInviteEvent(sessionItem, req, projectItem)
	return ret.(*project_member_api.GenInviteResponse), nil
}

func (apiImpl *ProjectMemberApiImpl) ListInvite(ctx context.Context, req *project_member_api.ListInviteRequest) (*project_member_api.ListInviteResponse, error) {
	emptyList := []*project_member_api.InviteInfo{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_member_api.ListInviteResponse{
			Code:           project_member_api.ListInviteResponse_CODE_WRONG_SESSION,
			ErrMsg:         "会话不存在",
			InviteInfoList: emptyList,
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_member_api.ListInviteResponse{
			Code:           project_member_api.ListInviteResponse_CODE_NO_PROJECT,
			ErrMsg:         "项目不存在",
			InviteInfoList: emptyList,
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_member_api.ListInviteResponse{
			Code:           project_member_api.ListInviteResponse_CODE_NO_PERMISSION,
			ErrMsg:         "没有权限",
			InviteInfoList: emptyList,
		}, nil
	} else if err != nil {
		return nil, err
	}
	if !(roleItem.BasicInfo.Admin || projectItem.OwnerUserId == sessionItem.UserId) {
		return &project_member_api.ListInviteResponse{
			Code:           project_member_api.ListInviteResponse_CODE_NO_PERMISSION,
			ErrMsg:         "没有权限",
			InviteInfoList: emptyList,
		}, nil
	}

	//清除过期的邀请
	err = project_dao.ProjectInviteDao.RemoveExpire(ctx, req.ProjectId, time.Now().UnixNano()/1e6)
	if err != nil {
		return nil, err
	}

	count, err := project_dao.ProjectInviteDao.Count(ctx, req.ProjectId)
	if err != nil {
		return nil, err
	}
	inviteItemList, err := project_dao.ProjectInviteDao.List(ctx, req.ProjectId, int64(req.Offset), int64(req.Limit))
	if err != nil {
		return nil, err
	}

	//补全用户信息
	userIdList := []string{}
	for _, inviteItem := range inviteItemList {
		userIdList = append(userIdList, inviteItem.CreateUserId)
	}
	userItemList, err := user_dao.UserInfoDao.ListById(ctx, userIdList)
	if err != nil {
		return nil, err
	}
	userItemMap := map[string]*user_dao.UserInfoDbItem{}
	for _, userItem := range userItemList {
		userItemMap[userItem.UserId] = userItem
	}

	infoList := []*project_member_api.InviteInfo{}
	for _, inviteItem := range inviteItemList {
		info := inviteItem.ToInviteInfo()
		userItem, ok := userItemMap[inviteItem.CreateUserId]
		if ok {
			info.CreateDisplayName = userItem.BasicInfo.DisplayName
			info.CreateLogoUri = userItem.BasicInfo.LogoUri
		}
		infoList = append(infoList, info)
	}
	return &project_member_api.ListInviteResponse{
		Code:           project_member_api.ListInviteResponse_CODE_OK,
		TotalCount:     count,
		InviteInfoList: infoList,
	}, nil
}

func (apiImpl *ProjectMemberApiImpl) RemoveInvite(ctx context.Context, req *project_member_api.RemoveInviteRequest) (*project_member_api.RemoveInviteResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_member_api.RemoveInviteResponse{
			Code:   project_member_api.RemoveInviteResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_member_api.RemoveInviteResponse{
			Code:   project_member_api.RemoveInviteResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_member_api.RemoveInviteResponse{
			Code:   project_member_api.RemoveInviteResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_member_api.RemoveInviteResponse{
			Code:   project_member_api.RemoveInviteResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	if !(roleItem.BasicInfo.Admin || projectItem.OwnerUserId == sessionItem.UserId) {
		return &project_member_api.RemoveInviteResponse{
			Code:   project_member_api.RemoveInviteResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = project_dao.ProjectInviteDao.Remove(sessCtx, req.ProjectId, req.InviteCode)
		if err != nil {
			return nil, err
		}
		return &project_member_api.RemoveInviteResponse{
			Code: project_member_api.RemoveInviteResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*project_member_api.RemoveInviteResponse), nil
}

func (apiImpl *ProjectMemberApiImpl) Join(ctx context.Context, req *project_member_api.JoinRequest) (*project_member_api.JoinResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_member_api.JoinResponse{
			Code:   project_member_api.JoinResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检测invite code
	inviteItem, err := project_dao.ProjectInviteDao.Get(ctx, req.InviteCode)
	if err != nil {
		return &project_member_api.JoinResponse{
			Code:   project_member_api.JoinResponse_CODE_WRONG_INVITE_CODE,
			ErrMsg: "错误的邀请码",
		}, nil
	}
	nowTime := time.Now().UnixNano() / 1e6
	if inviteItem.ExpireTime < nowTime {
		return &project_member_api.JoinResponse{
			Code:   project_member_api.JoinResponse_CODE_WRONG_INVITE_CODE,
			ErrMsg: "错误的邀请码",
		}, nil
	}
	//获取项目信息
	projectItem, err := project_dao.ProjectInfoDao.Get(ctx, inviteItem.ProjectId)
	if err != nil {
		return &project_member_api.JoinResponse{
			Code:   project_member_api.JoinResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	}
	if projectItem.Closed {
		return &project_member_api.JoinResponse{
			Code:   project_member_api.JoinResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = api_common.AddMember(sessCtx, nowTime, projectItem, sessionItem.UserId, "")
		if err != nil {
			return nil, err
		}

		return &project_member_api.JoinResponse{
			Code:      project_member_api.JoinResponse_CODE_OK,
			ProjectId: projectItem.ProjectId,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//记录事件
	go apiImpl.addJoinEvent(sessionItem, req, projectItem)
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), inviteItem.ProjectId, &notices_project.AddMemberNotice{
		ProjectId:    inviteItem.ProjectId,
		MemberUserId: sessionItem.UserId,
	})
	return ret.(*project_member_api.JoinResponse), nil
}

func (apiImpl *ProjectMemberApiImpl) Leave(ctx context.Context, req *project_member_api.LeaveRequest) (*project_member_api.LeaveResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_member_api.LeaveResponse{
			Code:   project_member_api.LeaveResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, err := project_dao.ProjectInfoDao.Get(ctx, req.ProjectId)
	if err != nil {
		return &project_member_api.LeaveResponse{
			Code:   project_member_api.LeaveResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	}
	if projectItem.OwnerUserId == sessionItem.UserId {
		return &project_member_api.LeaveResponse{
			Code:   project_member_api.LeaveResponse_CODE_NOT_ALLOW,
			ErrMsg: "项目创建人不能离开项目",
		}, nil
	}
	exist, err := project_dao.MemberInfoDao.Exist(ctx, req.ProjectId, sessionItem.UserId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &project_member_api.LeaveResponse{
			Code: project_member_api.LeaveResponse_CODE_OK,
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = api_common.RemoveMember(sessCtx, req.ProjectId, sessionItem.UserId)
		if err != nil {
			return nil, err
		}
		return &project_member_api.LeaveResponse{
			Code: project_member_api.LeaveResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//记录事件
	go apiImpl.addLeaveEvent(sessionItem, req, projectItem)
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_project.RemoveMemberNotice{
		ProjectId:    req.ProjectId,
		MemberUserId: sessionItem.UserId,
	})
	return ret.(*project_member_api.LeaveResponse), nil
}

func (apiImpl *ProjectMemberApiImpl) RemoveMember(ctx context.Context, req *project_member_api.RemoveMemberRequest) (*project_member_api.RemoveMemberResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_member_api.RemoveMemberResponse{
			Code:   project_member_api.RemoveMemberResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检测权限
	projectItem, _, userRoleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_member_api.RemoveMemberResponse{
			Code:   project_member_api.RemoveMemberResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_member_api.RemoveMemberResponse{
			Code:   project_member_api.RemoveMemberResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_member_api.RemoveMemberResponse{
			Code:   project_member_api.RemoveMemberResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	if !(sessionItem.UserId == projectItem.OwnerUserId || userRoleItem.BasicInfo.Admin) {
		return &project_member_api.RemoveMemberResponse{
			Code:   project_member_api.RemoveMemberResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	exist, err := project_dao.MemberInfoDao.Exist(ctx, req.ProjectId, req.MemberUserId)
	if err != nil {
		return nil, err
	}
	if !exist { //记录不存在
		return &project_member_api.RemoveMemberResponse{
			Code: project_member_api.RemoveMemberResponse_CODE_OK,
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = api_common.RemoveMember(sessCtx, req.ProjectId, req.MemberUserId)
		if err != nil {
			return nil, err
		}
		return &project_member_api.RemoveMemberResponse{
			Code: project_member_api.RemoveMemberResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	userItem, err := user_dao.UserInfoDao.Get(ctx, req.MemberUserId)
	if err != nil {
		return nil, err
	}
	go apiImpl.addRemoveMemberEvent(sessionItem, req, projectItem, userItem)
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_project.RemoveMemberNotice{
		ProjectId:    req.ProjectId,
		MemberUserId: req.MemberUserId,
	})
	return ret.(*project_member_api.RemoveMemberResponse), nil
}

func (apiImpl *ProjectMemberApiImpl) ListMember(ctx context.Context, req *project_member_api.ListMemberRequest) (*project_member_api.ListMemberResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_member_api.ListMemberResponse{
			Code:   project_member_api.ListMemberResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检测是否是项目成员
	projectItem, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_member_api.ListMemberResponse{
			Code:   project_member_api.ListMemberResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_member_api.ListMemberResponse{
			Code:   project_member_api.ListMemberResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	var memberItemList []*project_dao.MemberInfoDbItem
	if req.FilterByMemberUserId {
		memberItemList, err = project_dao.MemberInfoDao.ListMemberById(ctx, req.ProjectId, req.MemberUserIdList)
		if err != nil {
			return nil, err
		}
	} else {
		memberItemList, err = project_dao.MemberInfoDao.ListMember(ctx, req.ProjectId)
		if err != nil {
			return nil, err
		}
	}

	//获取用户信息
	userIdList := []string{}
	for _, memberItem := range memberItemList {
		userIdList = append(userIdList, memberItem.MemberUserId)
	}
	extraUserMap := map[string]*user_dao.UserInfoDbItem{}
	userItemList, err := user_dao.UserInfoDao.ListById(ctx, userIdList)
	if err != nil {
		return nil, err
	}
	for _, userItem := range userItemList {
		extraUserMap[userItem.UserId] = userItem
	}

	//获取简历访问权限
	accessItemList, err := user_dao.ResumeAccessDao.ListById(ctx, userIdList)
	if err != nil {
		return nil, err
	}
	accessItemMap := map[string]*user_dao.ResumeAccessDbItem{}
	for _, accessItem := range accessItemList {
		accessItemMap[accessItem.UserId] = accessItem
	}

	memberList := []*project_member_api.MemberInfo{}
	for _, memberItem := range memberItemList {
		logoUri := ""
		displayName := ""
		extraUser, ok := extraUserMap[memberItem.MemberUserId]
		if ok {
			logoUri = extraUser.BasicInfo.LogoUri
			displayName = extraUser.BasicInfo.DisplayName
		}
		memberList = append(memberList, memberItem.ToMemberInfo(logoUri, displayName))
	}

	//补充在线信息
	for _, memberInfo := range memberList {
		online, _ := dao.CacheDao.ExistUser(ctx, memberInfo.MemberUserId)
		memberInfo.Online = online
		memberInfo.IsCurUser = (memberInfo.MemberUserId == sessionItem.UserId)
		accessItem, ok := accessItemMap[memberInfo.MemberUserId]
		if ok {
			memberInfo.HasResume = accessItem.AllowProjectAccess
		}
	}
	//补充角色信息
	roleItemList, err := project_dao.MemberRoleDao.ListByProjectId(ctx, req.ProjectId)
	if err != nil {
		return nil, err
	}
	roleItemMap := map[string]*project_dao.RoleInfoDbItem{}
	for _, roleItem := range roleItemList {
		roleItemMap[roleItem.RoleId] = roleItem
	}
	for _, memberInfo := range memberList {
		roleItem, ok := roleItemMap[memberInfo.RoleId]
		if ok {
			memberInfo.RoleName = roleItem.BasicInfo.RoleName
			memberInfo.CanAdmin = roleItem.BasicInfo.Admin
		}
		if memberInfo.MemberUserId == projectItem.OwnerUserId {
			memberInfo.IsProjectOwner = true
			memberInfo.CanAdmin = true
		}
	}

	return &project_member_api.ListMemberResponse{
		Code:       project_member_api.ListMemberResponse_CODE_OK,
		MemberList: memberList,
	}, nil
}

func (apiImpl *ProjectMemberApiImpl) GetMember(ctx context.Context, req *project_member_api.GetMemberRequest) (*project_member_api.GetMemberResponse, error) {
	emptyMember := &project_member_api.MemberInfo{}
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_member_api.GetMemberResponse{
			Code:   project_member_api.GetMemberResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
			Member: emptyMember,
		}, nil
	}
	//检测权限
	projectItem, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_member_api.GetMemberResponse{
			Code:   project_member_api.GetMemberResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
			Member: emptyMember,
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_member_api.GetMemberResponse{
			Code:   project_member_api.GetMemberResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
			Member: emptyMember,
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_member_api.GetMemberResponse{
			Code:   project_member_api.GetMemberResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
			Member: emptyMember,
		}, nil
	}
	memberItem, err := project_dao.MemberInfoDao.Get(ctx, req.ProjectId, req.MemberUserId)
	if err != nil {
		return &project_member_api.GetMemberResponse{
			Code:   project_member_api.GetMemberResponse_CODE_NO_MEMBER,
			ErrMsg: "成员不存在",
		}, nil
	}

	//补充用户信息
	userItem, err := user_dao.UserInfoDao.Get(ctx, req.MemberUserId)
	if err != nil {
		return nil, err
	}
	member := memberItem.ToMemberInfo(userItem.BasicInfo.LogoUri, userItem.BasicInfo.DisplayName)
	//获取简历访问权限
	accessItemList, err := user_dao.ResumeAccessDao.ListById(ctx, []string{req.MemberUserId})
	if err != nil {
		return nil, err
	}
	if len(accessItemList) == 1 {
		member.HasResume = accessItemList[0].AllowProjectAccess
	}

	//补充在线信息
	online, _ := dao.CacheDao.ExistUser(ctx, req.MemberUserId)
	member.Online = online
	//补充角色信息
	roleItem, err := project_dao.MemberRoleDao.Get(ctx, req.ProjectId, memberItem.RoleId)
	if err == nil {
		member.RoleName = roleItem.BasicInfo.RoleName
		member.CanAdmin = roleItem.BasicInfo.Admin
		if member.MemberUserId == projectItem.OwnerUserId {
			member.IsProjectOwner = true
		}
		member.IsCurUser = (sessionItem.UserId == req.MemberUserId)
	}
	return &project_member_api.GetMemberResponse{
		Code:   project_member_api.GetMemberResponse_CODE_OK,
		Member: member,
	}, nil
}
